﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Timers;

namespace Prism.Core.Net.Tcp
{
    /// <summary>
    /// 连接类型。
    /// </summary>
    public class Connection : IDisposable, IElementHost
    {
        protected Connection()
        {
            StaticMember.SerializerType = SerializerType.Xaml;
        }

        /// <summary>
        /// 初始化连接类型的新实例。
        /// </summary>
        /// <param name="target">目标。</param>
        public Connection(ConnectionTarget target)
            : this()
        {
            this.TcpClient = new TcpClient();
            this.Target = target;
        }

        /// <summary>
        /// 初始化连接类型的新实例。
        /// </summary>
        /// <param name="tcpClient">Tcp客户端。</param>
        internal Connection(TcpClient tcpClient)
            : this()
        {
            this.TcpClient = tcpClient;
            this.Target = new ConnectionTarget() { IPEndPoint = (IPEndPoint)this.TcpClient.Client.RemoteEndPoint };
            this.OnNetworkHelperInitialization();
        }

        void NetworkHelper_ConnectionFailed(object sender, EventArgs e)
        {
            this.OnConnectionFailed(new EventArgs());
        }

        /// <summary>
        /// 开始接收数据，开始之后会以事件形式通知。
        /// </summary>
        public void StartReceiveData()
        {
            if (!this.IsConnected)
            {
                throw new InvalidOperationException();
            }
            this.OnNetworkHelperBeginRead();
        }

        /// <summary>
        /// 停止接收数据。
        /// </summary>
        public void StopReceiveData()
        {
            this.OnNetworkHelperStopRead();
        }

        protected virtual void OnNetworkHelperStopRead()
        {
            this.NetworkHelper.StopRead();
        }

        protected virtual void OnNetworkHelperBeginRead()
        {
            this.NetworkHelper.BeginRead(new ReadDataEndCallback(delegate(object data)
            {
                this.OnReadDataEndCallback(data);
            }));
        }

        protected void OnReadDataEndCallback(object data)
        {
            if (data != null)
            {
                this.OnDataReceived(new DataReceivedEventArgs() { Data = data });
            }
            else
            {
                throw new NullReferenceException();
            }
        }

        internal TcpClient TcpClient;

        /// <summary>
        /// 获取当前连接是否已经连接上目标。
        /// </summary>
        public bool IsConnected { get { return this.TcpClient.Connected; } }

        private NetworkHelper NetworkHelper;

        /// <summary>
        /// 获取或者设置要连接的目标。
        /// </summary>
        public ConnectionTarget Target
        {
            get;
            set;
        }

        /// <summary>
        /// 开始连接目标。
        /// </summary>
        /// <param name="callback">连接完毕的回调方法。</param>
        public void BeginConnect(ConnectedCallback callback)
        {
            this.TcpClient.BeginConnect(this.Target.IPEndPoint.Address, this.Target.IPEndPoint.Port, this.OnEndConnect, callback);
        }

        protected virtual void OnEndConnect(IAsyncResult ar)
        {
            var callback = ar.AsyncState as ConnectedCallback;
            if (ar.IsCompleted)
            {
                try
                {
                    this.TcpClient.EndConnect(ar);
                }
                catch (SocketException)
                {
                    callback(false);
                    return;
                }
                this.OnNetworkHelperInitialization(callback);
            }
        }

        protected virtual void OnNetworkHelperInitialization(ConnectedCallback callback)
        {
            this.NetworkHelper = new NetworkHelper(this.TcpClient);
            this.NetworkHelper.ConnectionFailed += new EventHandler(NetworkHelper_ConnectionFailed);
            callback(true);
        }

        protected virtual void OnNetworkHelperInitialization()
        {
            this.NetworkHelper = new NetworkHelper(this.TcpClient);
            this.NetworkHelper.ConnectionFailed += new EventHandler(NetworkHelper_ConnectionFailed);
        }

        /// <summary>
        /// 开始发送数据。
        /// </summary>
        /// <param name="data">要发送的数据。</param>
        /// <param name="callback">发送完毕后的回调方法。</param>
        public void BeginSendData(object data, DataSentCallback callback)
        {
            this.OnNetworkHelperBeginWrite(data, callback);
        }

        protected virtual void OnNetworkHelperBeginWrite(object data, DataSentCallback callback)
        {
            this.NetworkHelper.BeginWrite(data, new WriteDataEndCallback(delegate(bool completed)
            {
                this.OnWriteDataEndCallback(completed, callback);
            }));
        }

        protected void OnWriteDataEndCallback(bool completed, DataSentCallback callback)
        {
            if (callback != null)
            {
                if (completed)
                    callback(true);
                else
                    callback(false);
            }
        }

        /// <summary>
        /// 当接收到新数据时引发的事件。
        /// </summary>
        public event EventHandler<DataReceivedEventArgs> DataReceived;

        /// <summary>
        /// 当连接遇到意外断开时引发的事件。
        /// </summary>
        public event EventHandler ConnectionFailed;

        protected void OnDataReceived(DataReceivedEventArgs e)
        {
            if (this.DataReceived != null) { this.DataReceived(this, e); }
        }


        protected void OnConnectionFailed(EventArgs e)
        {
            if (this.ConnectionFailed != null)
            {
                lock (this.ConnectionFailed)
                {
                    if (this.ConnectionFailed != null && !this.IsConnectionFailed)
                    {
                        this.ConnectionFailed(this, e);
                        if (this.AutoStopReceiveData)
                        {
                            this.StopReceiveData();
                        }
                        this.IsConnectionFailed = true;
                    }
                }
            }
        }

        private volatile bool IsConnectionFailed = false;

        private bool autoStopReceiveData = true;

        /// <summary>
        /// 获取或者设置当链接意外断开时是否自动停止接收数据，默认为 True。
        /// </summary>
        public bool AutoStopReceiveData
        {
            get { return autoStopReceiveData; }
            set { autoStopReceiveData = value; }
        }


        public virtual void Dispose()
        {
            if (this.NetworkHelper != null)
            {
                this.ConnectionFailed = null;
                this.DataReceived = null;
                this.NetworkHelper.Dispose();
            }
        }

        public object Host
        {
            get;
            set;
        }
    }
}
